﻿using EmailHelper.Model;
using MailKit;
using MailKit.Net.Imap;
using MailKit.Security;
using System;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;

namespace EmailHelper.Common
{
    /// <summary>
    /// 邮箱服务器连接
    /// </summary>
    public class EmailServerConnect
    {
        /// <summary>
        /// 连接邮箱服务器并验证客户端身份
        /// </summary>
        /// <param name="client"></param>
        /// <param name="serverConfigurationEntity"></param>
        /// <returns></returns>
        public static bool ConnectServer(MailService client, ServerConfigurationEntity serverConfigurationEntity)
        {
            try
            {
                // For demo-purposes, accept all SSL certificates (in case the server supports STARTTLS)  
                //client.ServerCertificateValidationCallback = (s, c, h, e) => true;
                client.ServerCertificateValidationCallback = MySslCertificateValidationCallback;//设置一个回调函数来验证服务器证书。

                //使用SSL协议。。//此时会去检测 服务器证书是否可信，可信才会连接成功。检测结果通过MySslCertificateValidationCallback 给出。。方法的结果 若为true则继续；若为false则会抛出异常，catch捕获。
                client.Connect(serverConfigurationEntity.Host, serverConfigurationEntity.Port, serverConfigurationEntity.IsSsl ? SecureSocketOptions.SslOnConnect : SecureSocketOptions.None);
                // Note: since we don't have an OAuth2 token, disable  
                // the XOAUTH2 authentication mechanism.  
                client.AuthenticationMechanisms.Remove("XOAUTH2");
                //验证登录信息，输入账号和密码登录。
                client.Authenticate(serverConfigurationEntity.Account, serverConfigurationEntity.Password); 
                return true;
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());
                return false;
            }
        }
        /// <summary>
        ///  回调函数，返回服务器的一些信息
        /// </summary>
        /// <param name="sender">"imap.163.com"</param>
        /// <param name="certificate">邮箱服务器的证书信息</param>
        /// <param name="chain"></param>
        /// <param name="sslPolicyErrors"></param>
        /// <returns></returns>
        static bool MySslCertificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
        {
            // If there are no errors, then everything went smoothly.
            if (sslPolicyErrors == SslPolicyErrors.None)
                return true;

            // Note: MailKit will always pass the host name string as the `sender` argument.
            var host = (string)sender;

            if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateNotAvailable) != 0)
            {
                // This means that the remote certificate is unavailable. Notify the user and return false.
                Console.WriteLine("The SSL certificate was not available for {0}", host);
                return false;
            }

            if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateNameMismatch) != 0)
            {
                // This means that the server's SSL certificate did not match the host name that we are trying to connect to.
                var certificate2 = certificate as X509Certificate2;
                var cn = certificate2 != null ? certificate2.GetNameInfo(X509NameType.SimpleName, false) : certificate.Subject;

                Console.WriteLine("The Common Name for the SSL certificate did not match {0}. Instead, it was {1}.", host, cn);
                return false;
            }

            // The only other errors left are chain errors.
            Console.WriteLine("The SSL certificate for the server could not be validated for the following reasons:");

            // The first element's certificate will be the server's SSL certificate (and will match the `certificate` argument)
            // while the last element in the chain will typically either be the Root Certificate Authority's certificate -or- it
            // will be a non-authoritative self-signed certificate that the server admin created. 
            foreach (var element in chain.ChainElements)
            {
                // Each element in the chain will have its own status list. If the status list is empty, it means that the
                // certificate itself did not contain any errors.
                if (element.ChainElementStatus.Length == 0)
                    continue;

                Console.WriteLine("\u2022 {0}", element.Certificate.Subject);
                foreach (var error in element.ChainElementStatus)
                {
                    // `error.StatusInformation` contains a human-readable error string while `error.Status` is the corresponding enum value.
                    Console.WriteLine("\t\u2022 {0}", error.StatusInformation);
                }
            }
            return false;
        }

        /// <summary>
        /// 创建邮件日志文件
        /// </summary>
        /// <returns></returns>
        public static string CreateMailLog()
        {
            var folder = AppDomain.CurrentDomain.BaseDirectory + "/DocumentLog/";
            if (!Directory.Exists(folder))
            {
                Directory.CreateDirectory(folder);
            }
            var logPath = folder + DateTime.Now.ToUniversalTime().ToString("yyyy-MM-dd HH-mm-ss") + ".txt";

            if (File.Exists(logPath)) return logPath;
            var fs = File.Create(logPath);
            fs.Close();
            return logPath;

        }
    }
}